package com.example.demo.threadPool_countDownLatch.plus;

import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @author peter
 * @Date 2021/8/13 9:45 上午
 * @Classname AnimalCountThread
 * @Description codeReview
 */
@Slf4j
public class AnimalCountThread2 {
    /**
     * 客资id
     */
    private static List<Integer> userIds = new ArrayList<>();

    /**
     * 最大查询数
     */
    private static Integer MAX_NUM = 1;

    private static final Logger logger = LogManager.getLogger(AnimalCountThread2.class.getName());

    /**
     * 名称： 主线程和其他线程, 主线程唯一
     * <p>
     * 1: 高并发场景: 假设现在要去其他服务端进行RPC查询,要通过用户id拿到对应的用户对象
     * 2: 假设一个线程效率最高是处理500条,超过则开启其他线程去查询,当作小弟
     * 2.1: 未异步的问题在于: 请求->响应, 中间是十分耗时的, 为了提高效率,使用异步
     * 异步的好处是可以开启其他线程(假设两个): 请求-->请求-->响应-->响应。
     * 举例子:
     * 未异步: 当前有1000人来取号,若只有一个柜台,那么办理业务十分耗时
     * 异步:   当前有2个柜台, 每个柜台允许500人排队,这样大大提高效率
     * 3: 其他线程的可以按照用户id总数/最大查询数, 然后取整, 一般使用countDownLatch来统计其他线程数
     */
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        logger.info("开始时间:{}", LocalDateTime.now());
        for (int i = 0; i < 10; i++) {
            userIds.add(i);
        }
        if (userIds.size() > MAX_NUM) {
            Integer num = ((Double) Math.ceil(userIds.size() / MAX_NUM)).intValue();
            List<User> synchronizedList = new CopyOnWriteArrayList();
            for (Integer i = 0; i < num; i++) {
                int finalI = i;
                Future<List<User>> submit = ThreadpoolConfig.CUSTOMER_EXECUTOR.submit(() -> {
                    int formIndex = finalI * MAX_NUM;
                    int endIndex = (finalI + 1) * MAX_NUM - 1;
                    List<Integer> idsBySub = userIds.subList(formIndex, endIndex);
                    return getUserById(idsBySub);
                });
                //调用了get(),就会阻塞其他线程
                if (submit.get()!=null) {
                    List<User> users = submit.get();
                    synchronizedList.addAll(users);
                }
            }
            System.out.println("并发情况:" + synchronizedList);
            System.out.println("数据量:" + synchronizedList.size());
        } else {
            System.out.println("普通情况:" + getUserById(userIds));
        }
        logger.info("结束时间:{}", LocalDateTime.now());
    }

    /**
     * 通过userId去查找User对象, 假设这个接口的api耗时5秒
     *
     * @param userIds
     * @return
     */
    public static List<User> getUserById(List<Integer> userIds) throws InterruptedException {
        List<User> userList = new ArrayList<>();
        System.out.println("线程进来了..." + Thread.currentThread().getName());
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setId(Integer.valueOf(i));
            user.setName(String.valueOf(i));
            userList.add(user);
        }
        Thread.sleep(5000);
        return userList;
    }
}


